package project.crawler.parser;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import project.model.adt.Answer;
import project.model.adt.Question;

public class QuestionParser {

	private static final int MIN_ANSWER_NUMBER = 5;

	public static Question parseQuestion(String html, long questionID) {
		Document doc = org.jsoup.parser.Parser.parse(html, "");

		Element questionDiv = doc.body().getElementById("question");
		Element answersDiv = doc.body().getElementById("answers");

		String title = getTitle(doc.body());
		String description = getDescription(questionDiv);

		if (!questionDiv.getElementsByClass("community-wiki").isEmpty()) {
			throw new RuntimeException("Community-Wiki");
		}

		Element signatureTd = ParserUtils.getElement(questionDiv, "class",
				"post-signature owner", "td");

		long dateAsked = getDateAsked(signatureTd);

		long askerId = getAskerID(signatureTd);

		long votes = getVotes(questionDiv);

		List<Answer> answers = getAnswers(answersDiv);

		return new Question(questionID, title, description, dateAsked, askerId,
				votes, answers);
	}

	private static final Pattern ANSWER_ID_PATTERN = Pattern
			.compile("\\Qanswer-\\E\\d+");

	private static List<Answer> getAnswers(Element answersDiv) {
		Elements elems = answersDiv.getElementsByAttributeValueMatching("id",
				ANSWER_ID_PATTERN);
		List<Answer> answers = new ArrayList<Answer>();
		for (Element answerDiv : elems) {
			if (!answerDiv.getElementsByClass("community-wiki").isEmpty()) {
				System.out.println("Community Wiki answer ignored.");
				continue;
			}
			answers.add(parseAnswer(answerDiv));
		}

		if (answers.size() < MIN_ANSWER_NUMBER) {
			throw new RuntimeException("Not enough answers: " + elems.size());
		}

		return answers;
	}

	private static Answer parseAnswer(Element answerDiv) {
		Element signatureDiv = getAnswerSignatureDiv(answerDiv);

		long answerID = Long.parseLong(answerDiv.attr("data-answerid"));
		long userID = getAskerID(signatureDiv);
		String description = ParserUtils.getElement(answerDiv, "class",
				"post-text", "div").html();
		long dateAnswered = getDateAsked(signatureDiv);
		long votes = getVotes(answerDiv);

		return new Answer(answerID, userID, description, dateAnswered, votes);
	}

	private static Element getAnswerSignatureDiv(Element answerDiv) {
		Elements elems = answerDiv.getElementsByClass("user-info");
		for (Element elem : elems) {
			if (elem.html().contains("answered")) {
				return elem;
			}
		}
		throw new RuntimeException("Answer User Signature Not Found.");
	}

	private static long getVotes(Element questionDiv) {
		Elements elems = questionDiv.getElementsByClass("vote-count-post");
		Element elem = ParserUtils.assertOneElement(elems, "span");
		return Long.parseLong(elem.html());

	}

	private static Pattern USER_HREF_PATTERN = Pattern
			.compile("\\Q/users/\\E(\\d+)\\/.*");

	private static long getAskerID(Element signatureTd) {
		Element details = ParserUtils.getElement(signatureTd, "class",
				"user-details", "div");
		String href = details.child(0).attr("href");
		return ParserUtils.getLongFromPattern(USER_HREF_PATTERN, href);
	}

	private static long getDateAsked(Element signatureTd) {
		Element elem2 = ParserUtils.getElement(signatureTd, "class",
				"user-action-time", "div");
		Element span = ParserUtils.assertOneElement(
				elem2.getElementsByTag("span"), "span");
		return ParserUtils.parseDate(span.attr("title"));
	}

	private static String getTitle(Element body) {
		Element elem = ParserUtils.getElement(body, "id", "question-header",
				"div");
		return elem.child(0).child(0).html();
	}

	private static String getDescription(Element questionDiv) {
		Element elem = ParserUtils.getElement(questionDiv, "itemprop",
				"description", "div");
		return elem.html();
	}
}
